package raft

import (
	"fmt"
	"log"
	"math/rand"
	"net"
	"sync"
	"time"

	"google.golang.org/grpc"
)

const (
	Follower State = iota
	Candidate
	Leader
)

type State int64

type RaftNode struct {
	mu                sync.Mutex
	id                int32
	currentTerm       int64
	votedFor          int32
	state             State
	logs              []*LogEntry
	commitIndex       int64
	lastApplied       int64
	lastSnapshotIndex int64
	lastSnapshotTerm  int64
	nextIndex         map[int32]int64
	matchIndex        map[int32]int64
	peers             map[int32]*Peer
	persister         Persister
	applyCh           chan ApplyMsg
	server            *grpc.Server
	listener          net.Listener
	electionTimeout   time.Duration
	lastHeard         time.Time
	stateMachine      StateMachine
	stopChan          chan struct{}
}

type ApplyMsg struct {
	CommandValid bool
	Command      []byte
	CommandIndex int64
}

type StateMachine interface {
	Apply([]byte) ([]byte, error)
	Snapshot() ([]byte, error)
	ApplySnapshot([]byte) error
}

func MakeRaft(id int32, peers map[int32]string, port int, persister Persister, applyCh chan ApplyMsg) *RaftNode {
	// 初始化节点
	node := &RaftNode{
		id:                id,
		state:             Follower,
		currentTerm:       0,
		votedFor:          -1,
		logs:              []*LogEntry{{Term: 0, Index: 0}}, // 初始空日志
		commitIndex:       0,
		lastApplied:       0,
		lastSnapshotIndex: 0,
		lastSnapshotTerm:  0,
		nextIndex:         make(map[int32]int64),
		matchIndex:        make(map[int32]int64),
		peers:             make(map[int32]*Peer),
		persister:         persister,
		applyCh:           applyCh,
		electionTimeout:   time.Millisecond * time.Duration(150+rand.Intn(150)),
		lastHeard:         time.Now(),
		stopChan:          make(chan struct{}),
	}

	// 初始化对等节点
	for peerID, addr := range peers {
		if peerID == id {
			continue
		}
		node.peers[peerID] = NewPeer(peerID, addr, node)
	}

	// 设置gRPC监听
	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
	if err != nil {
		log.Fatalf("Raft %d failed to listen: %v", id, err)
	}

	node.server = grpc.NewServer()
	RegisterRaftServer(node.server, node)
	node.listener = lis

	return node
}

func (n *RaftNode) Start() {
	n.loadPersistedState()

	// 启动gRPC服务
	go func() {
		if err := n.server.Serve(n.listener); err != nil {
			log.Fatalf("Raft %d failed to serve: %v", n.id, err)
		}
	}()

	// 启动状态机应用器
	go n.applier()

	// 启动主循环
	go n.run()

	log.Printf("Raft node %d started at %s", n.id, n.listener.Addr())
}

func (n *RaftNode) Stop() {
	close(n.stopChan)
	if n.server != nil {
		n.server.Stop()
	}
}
